/*-------------------------------------------------------------------------
 *
 * partbounds.h
 *
 * Copyright (c) 2007-2022, PostgreSQL Global Development Group
 *
 * src/include/partitioning/partbounds.h
 *
 *-------------------------------------------------------------------------
 */
#ifndef PARTBOUNDS_H
#define PARTBOUNDS_H

#include "fmgr.h"
#include "parser/parse_node.h"
#include "partitioning/partdefs.h"

struct RelOptInfo;				/* 避免在此处包含 pathnodes.h */


/*
 * PartitionBoundInfoData 封装了一组分区边界。它通常与分区表作为
 * 其分区描述符的一部分相关联，但也可以用于表示一个虚拟的
 * 分区表，例如计划器中的分区连接表。
 *
 * 已知为 NULL 的列表分区数据从未放入
 * datums 数组中。相反，它使用 null_index 字段进行跟踪。
 *
 * 在范围分区的情况下，ndatums 通常远少于
 * 2 * nparts，因为在大多数常见情况下，分区的上界和下一个
 * 分区的下界是相同的，且我们只存储其中一个（上界）。
 * 在哈希分区的情况下，ndatums 将与分区数量相同。
 *
 * 对于范围和列表分区的表，datums 是一个包含
 * key->partnatts 个数据的 datum 元组数组。对于哈希分区的表，它是一个
 * 包含 2 个数据的 datum 元组数组，模数和余数，分别对应于
 * 给定分区。
 *
 * datums 数组中的数据按 increasing order 排列，由
 * 函数 qsort_partition_rbound_cmp()、qsort_partition_list_value_cmp() 和
 * qsort_partition_hbound_cmp() 分别定义用于范围、列表和哈希分区的表。
 * 对于范围和列表分区，这简单意味着 datums 数组中的数据
 * 按由分区键的操作符类和排序规则定义的 increasing order 排列。
 *
 * 在列表分区的情况下，indexes 数组为
 * 每个 datum-array 条目存储一个条目，即接受与该数据匹配的
 * 行的分区索引。因此 nindexes == ndatums。
 *
 * 在范围分区的情况下，indexes 数组为每个不同的范围数据存储一个条目，
 * 该条目是该数据的上界的分区索引（或 -1 表示没有分区的“间隙”）。
 * 拥有额外的 -1 条目表示超出最后一个范围数据的值是方便的，
 * 因此 nindexes == ndatums + 1。
 *
 * 在哈希分区的情况下，indexes 数组中的条目数量
 * 与所有分区中的最大模数相同（这是所有分区模数的倍数），因此
 * nindexes == greatest modulus。indexes 数组是根据哈希键的余数模
 * 最大模数进行索引的，它包含接受该余数的分区索引，或者 -1 如果
 * 没有该余数的分区。
 *
 * 对于列表分区的表，我们跟踪可能是“交错”分区的分区索引。
 * 被认为是交错的分区是允许多个值，并且存在至少一个
 * 其他分区可以包含位于这些值之间的值。例如，如果存在一个
 * PARTITION FOR VALUES IN(3,5) 的分区，另一个分区存在
 * PARTITION FOR VALUES IN (4)，那么 IN(3,5) 的分区就是一个交错
 * 的分区。由于默认分区可以包含任何不属于其他分区的值，
 * 因此这同样是可能的。此字段仅证明特定分区不是交错分区，而不是证明它是交错的。
 * 当我们不确定时，我们将分区标记为交错分区。交错分区字段仅在
 * RELOPT_BASEREL 和 RELOPT_OTHER_MEMBER_REL 中设置，始终在连接
 * 关系中保持 NULL。
 */
typedef struct PartitionBoundInfoData
{
	char		strategy;		/* 哈希、列表或范围？ */
	int			ndatums;		/* datums[] 数组的长度 */
	Datum	  **datums;
	PartitionRangeDatumKind **kind; /* 每个范围边界数据的类型；
									 * 哈希和列表分区表为 NULL */
	Bitmapset  *interleaved_parts;	/* 可能是交错的分区的分区索引。见上文。仅在 LIST 分区表中设置 */
	int			nindexes;		/* indexes[] 数组的长度 */
	int		   *indexes;		/* 分区索引 */
	int			null_index;		/* 接受 NULL 的分区索引；如果没有则为 -1 */
	int			default_index;	/* 默认分区的索引；如果没有则为 -1 */
} PartitionBoundInfoData;

#define partition_bound_accepts_nulls(bi) ((bi)->null_index != -1)
#define partition_bound_has_default(bi) ((bi)->default_index != -1)

extern int	get_hash_partition_greatest_modulus(PartitionBoundInfo b);
extern uint64 compute_partition_hash_value(int partnatts, FmgrInfo *partsupfunc,
										   Oid *partcollation,
										   Datum *values, bool *isnull);
extern List *get_qual_from_partbound(Relation parent,
									 PartitionBoundSpec *spec);
extern PartitionBoundInfo partition_bounds_create(PartitionBoundSpec **boundspecs,
												  int nparts, PartitionKey key, int **mapping);
extern bool partition_bounds_equal(int partnatts, int16 *parttyplen,
								   bool *parttypbyval, PartitionBoundInfo b1,
								   PartitionBoundInfo b2);
extern PartitionBoundInfo partition_bounds_copy(PartitionBoundInfo src,
												PartitionKey key);
extern PartitionBoundInfo partition_bounds_merge(int partnatts,
												 FmgrInfo *partsupfunc,
												 Oid *partcollation,
												 struct RelOptInfo *outer_rel,
												 struct RelOptInfo *inner_rel,
												 JoinType jointype,
												 List **outer_parts,
												 List **inner_parts);
extern bool partitions_are_ordered(PartitionBoundInfo boundinfo,
								   Bitmapset *live_parts);
extern void check_new_partition_bound(char *relname, Relation parent,
									  PartitionBoundSpec *spec,
									  ParseState *pstate);
extern void check_default_partition_contents(Relation parent,
											 Relation defaultRel,
											 PartitionBoundSpec *new_spec);

extern int32 partition_rbound_datum_cmp(FmgrInfo *partsupfunc,
										Oid *partcollation,
										Datum *rb_datums, PartitionRangeDatumKind *rb_kind,
										Datum *tuple_datums, int n_tuple_datums);
extern int	partition_list_bsearch(FmgrInfo *partsupfunc,
								   Oid *partcollation,
								   PartitionBoundInfo boundinfo,
								   Datum value, bool *is_equal);
extern int	partition_range_datum_bsearch(FmgrInfo *partsupfunc,
										  Oid *partcollation,
										  PartitionBoundInfo boundinfo,
										  int nvalues, Datum *values, bool *is_equal);
extern int	partition_hash_bsearch(PartitionBoundInfo boundinfo,
								   int modulus, int remainder);

#endif							/* PARTBOUNDS_H */
